#include <functional>
#include <string.h>
#include <iostream>
#include <fstream>
#include <sstream>
#define PI 3.14

using namespace std;

class Figure{
public:
    using DisplayCallBack = function<void()>;
    using AreaCallBack = function<double()>;

    void setDisplayCallBack(DisplayCallBack &&cb){
        _displayCallBack = move(cb);
    }

    void setAreaCallBack(AreaCallBack &&ab){
        _areaCallBack = move(ab);
    }

    void handleDisplayCallBack() const{
        if(_displayCallBack){
            _displayCallBack();
        }
    }

    double handleAreaCallBack()const{
        if(_areaCallBack){
           return  _areaCallBack();
        }
        return 0.0;
    }
private:
    DisplayCallBack _displayCallBack;
    AreaCallBack _areaCallBack;
};

class Rectangle{
public:
    Rectangle(int l = 0,int w = 0)
    :_lenth(l)
    ,_width(w)
    {

    }

    void display(int x) const{
        cout << "Rectangle" << " ";
    }

    double area()const{
        return _lenth * _width;
    }
private:
    int _lenth;
    int _width;
};

class Circle{
public:
    Circle(int r = 0)
    :_radius(r)
    {

    }

    void show() const{
        cout << "Circle" << " ";
    }

    double getArea(){
        return PI * _radius * _radius;
    }
private:
    int _radius;
};

class Triangle{
public:
    Triangle(int b = 0,int h = 0)
    :_base(b)
    ,_high(h)
    {

    }

    void print() const{
        cout << "Triangle" << " ";
    }

    double getArea() const{
        return 0.5 * _base * _high;
    }
private:
    int _base;
    int _high;
};

void func(Figure & fig){
    fig.handleDisplayCallBack();
    cout << "s = " << fig.handleAreaCallBack() << endl;
}
void test(){
    Rectangle r(10,5);
    Circle c(8);
    Triangle t(3,4);

    Figure fig;
    fig.setDisplayCallBack(bind(&Rectangle::display,&r,1));
    fig.setAreaCallBack(bind(&Rectangle::area,&r));
    func(fig);

    fig.setDisplayCallBack(bind(&Circle::show,&c));
    fig.setAreaCallBack(bind(&Circle::getArea,&c));
    func(fig);

    fig.setDisplayCallBack(bind(&Triangle::print,&t));
    fig.setAreaCallBack(bind(&Triangle::getArea,&t));
    func(fig);
}

int main()
{
    test();
    return 0;
}

